package com.andreamerla.petslife.activity;

import android.content.Intent;
import android.location.Address;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.andreamerla.petslife.R;
import com.andreamerla.petslife.manager.AlertDialogManager;
import com.andreamerla.petslife.manager.GooglePlacesManager;
import com.andreamerla.petslife.manager.NavigationManager;
import com.andreamerla.petslife.model.Place;
import com.andreamerla.petslife.model.PlaceList;
import com.andreamerla.petslife.model.Placemark;
import com.andreamerla.petslife.util.Response;
import com.andreamerla.petslife.util.Utils;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: a.merla
 * Date: 17/07/13
 * Time: 15.09
 */
public class VetMapActivity extends GpsActivity implements GoogleMap.InfoWindowAdapter, GoogleMap.OnInfoWindowClickListener {
    private static final float INITIAL_MAP_ZOOM_LEVEL = 8;

    private GoogleMap googleMap;
    private List<Placemark> placemarkList = new ArrayList<Placemark>();
    private HashMap<Marker, Placemark> markerPlacemarkHashMap = new HashMap<Marker, Placemark>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.vet_map_layout);

        initMap();

        new LoadKMLDataTask().execute();
    }

    private void initMap() {
        // Controlla la presenza sul dispositivo di Google Play services APK
        if (!Utils.checkGooglePlayServices(this))
            return;

        setUpMapIfNeeded();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == Utils.GOOGLE_PLAY_SERVICES_REQUEST_CODE)
            if (resultCode == RESULT_OK)
                initMap();
    }

    private void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the map
        if (googleMap == null) {
            googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();

            // Check if we were successful in obtaining the map
            if (googleMap != null) {
                // The Map is verified: it is now safe to manipulate the map
                googleMap.setMyLocationEnabled(true);

                googleMap.setInfoWindowAdapter(this);
                googleMap.setOnInfoWindowClickListener(this);

                // Update position and zoom map
                Location location = gpsTracker.getLocation();
                if (location != null) {
                    LatLng position = new LatLng(location.getLatitude(), location.getLongitude());
                    if (googleMap != null)
                        googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position, INITIAL_MAP_ZOOM_LEVEL));
                }
            }
        }
    }

    public View getInfoWindow(Marker marker) {
        return null; // Use getInfoContents method to fill the info window
    }

    public View getInfoContents(Marker marker) {
        Placemark placemark = markerPlacemarkHashMap.get(marker);

        View view = getLayoutInflater().inflate(R.layout.vet_map_info_window_layout, null);

        // Vet name
        TextView tvVetName = (TextView) view.findViewById(R.id.tv_vet_name);
        tvVetName.setText(placemark.getName());

        // Vet address
        TextView tvVetAddress = (TextView) view.findViewById(R.id.tv_vet_address);
        Address address = placemark.getAddress();
        if (address != null) {
            StringBuilder addressString = new StringBuilder();
            for (int i = 0; i < address.getMaxAddressLineIndex(); i++) {
                addressString.append(address.getAddressLine(i));
                if (i < address.getMaxAddressLineIndex() - 1)
                    addressString.append("\n");
            }
            tvVetAddress.setText(addressString);
        }

        // Vet description
        TextView tvVetDescription = (TextView) view.findViewById(R.id.tv_vet_description);
        tvVetDescription.setVisibility(View.GONE);
//        if (placemark.getDescription() != null)
//            tvVetDescription.setText(Html.fromHtml(placemark.getDescription()));

        return view;
    }

    public void onInfoWindowClick(Marker marker) {
        Placemark placemark = markerPlacemarkHashMap.get(marker);

        NavigationManager.startNavigationTo(this, placemark.getLatLng());
    }

    private class LoadKMLDataTask extends AsyncTask<Void, Placemark, Response> {
        @Override
        protected Response doInBackground(Void... voids) {
            Document doc = null;
            try {
                doc = downloadKML();
                readKML(doc);
            } catch (IOException e) {
                e.printStackTrace();
                return Response.ERROR_DOWNLOADING_KML;
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
                return Response.ERROR_DOWNLOADING_KML;
            } catch (SAXException e) {
                e.printStackTrace();
                return Response.ERROR_DOWNLOADING_KML;
            } catch (Exception e) {
                e.printStackTrace();
                return Response.ERROR_PARSING_KML;
            }
            return Response.OK;
        }

        private Document downloadKML() throws IOException, ParserConfigurationException, SAXException {
            URL url = new URL("https://www.google.com/maps/ms?authuser=0&vps=2&hl=it&ie=UTF8&msa=0&output=kml&msid=215762953792784054780.0004d5fce5b2f75649817");
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            return db.parse(new InputSource(url.openStream()));
        }

        private void readKML(Document doc) throws Exception {
            doc.getDocumentElement().normalize();

            NodeList nodeList = doc.getElementsByTagName("Placemark");

            for (int index = 0; index < nodeList.getLength(); index++) {
                Element placemarkElement = (Element) nodeList.item(index);
                Placemark placemark = new Placemark();
                NodeList placemarkChildren = placemarkElement.getChildNodes();
                for (int i = 0; i < placemarkChildren.getLength(); i++) {
                    Node childNode = placemarkChildren.item(i);
                    if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                        Element child = (Element) placemarkChildren.item(i);
                        if (child.getTagName().equals("name") && child.getChildNodes().getLength() > 0)
                            placemark.setName(child.getChildNodes().item(0).getNodeValue());
                        else if (child.getTagName().equals("description") && child.getChildNodes().getLength() > 0)
                            placemark.setDescription(child.getChildNodes().item(0).getNodeValue());
                        else if (child.getTagName().equals("Point")) {
                            NodeList coordinatesList = child.getElementsByTagName("coordinates");
                            if (coordinatesList.getLength() > 0) {
                                NodeList coordinatesList2 = coordinatesList.item(0).getChildNodes();
                                if (coordinatesList2.getLength() > 0) {
                                    String coordinatesString = coordinatesList2.item(0).getNodeValue();
                                    String[] coordinates = coordinatesString.split(",");
                                    if (coordinates.length >= 2)
                                        placemark.setLatLng(new LatLng(Double.parseDouble(coordinates[1]), Double.parseDouble(coordinates[0])));
                                }
                            }
                        }
                    }
                }
                placemarkList.add(placemark);
                publishProgress(placemark);
            }
        }

        @Override
        protected void onProgressUpdate(Placemark... placemarks) {
            super.onProgressUpdate(placemarks);

            if (placemarks.length == 0)
                return;

            addMarker(placemarks[0]);
        }

        @Override
        protected void onPostExecute(Response response) {
            super.onPostExecute(response);

            if (response != Response.OK)
                Log.e(Utils.getLogTag(this.getClass()), response.getDescription());

            new LoadAddressesTask().execute();

            Log.d(Utils.getLogTag(this.getClass()), "Placemarks total number: " + placemarkList.size());
            Log.d(Utils.getLogTag(this.getClass()), "Markers total number: " + markerPlacemarkHashMap.size());
        }

        private void addMarkers() {
            for (Placemark placemark : placemarkList)
                addMarker(placemark);
        }

        private void addMarker(Placemark placemark) {
            if (googleMap == null)
                return;

            Marker marker = googleMap.addMarker(
                    new MarkerOptions()
                            .position(placemark.getLatLng())
                            .title(placemark.getName())
                            .snippet(placemark.getDescription())
            );
            markerPlacemarkHashMap.put(marker, placemark);
        }
    }

    private class LoadAddressesTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            for (Placemark placemark : placemarkList)
                placemark.loadAddress();
            return null;
        }
    }

    private class LoadPlacesTask extends AsyncTask<Void, Void, Void> {
        PlaceList nearPlaces;

        @Override
        protected Void doInBackground(Void... voids) {
            try {
                Location location = gpsTracker.getLocation();
                String types = "veterinary_care";
                int radius = 10000; // 10 kilometers
                boolean rankByDistance = true;

                if (location != null)
                    nearPlaces = GooglePlacesManager.nearbySearch(location.getLatitude(), location.getLongitude(), radius, types, rankByDistance);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            String status = nearPlaces.status;

            if (status.equals(Response.OK.getName())) {
                if (nearPlaces.results != null) {
                    for (Place p : nearPlaces.results) {
                        Log.d(Utils.getLogTag(this.getClass()), "Place found: " + p.name);
                    }
                }
            } else {
                Response response = Response.getResponseByName(status);
                if (response == null)
                    response = Response.ERROR;
                AlertDialogManager.showAlertDialog(VetMapActivity.this, response.getName(), response.getDescription());
            }
        }
    }
}
